Java并发编程原理与实战五:创建线程的多种方式
一、继承Thread类
public class Demo1 extends Thread { public Demo1(String name) { super(name); } @Override public void run() { while(!interrupted()) { System.out.println(getName() + "线程执行了 .. "); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Demo1 d1 = new Demo1("first-thread"); Demo1 d2 = new Demo1("second-thread"); d1.start(); d2.start(); // d1.stop(); d1.interrupt(); } }
二、实现Runnable 接口
/** * 作为线程任务存在 * * @author worker * */ public class Demo2 implements Runnable { @Override public void run() { while(true) { System.out.println("thread running ..."); } } public static void main(String[] args) { Thread thread = new Thread(new Demo2()); thread.start(); } }
三、匿名内部类的方式
public class Demo3 { public static void main(String[] args) { /*new Thread() { public void run() { System.out.println("thread start .."); }; }.start();*/ /*new Thread(new Runnable() { @Override public void run() { System.out.println("thread start .."); } }).start();*/ new Thread(new Runnable() { @Override public void run() { System.out.println("runnable"); } }) { public void run() { System.out.println("sub"); }; }.start(); } }
四、带返回值的线程
import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class Demo4 implements Callable<Integer> { public static void main(String[] args) throws Exception { Demo4 d = new Demo4(); FutureTask<Integer> task = new FutureTask<>(d); Thread t = new Thread(task); t.start(); System.out.println("我先干点别的。。。"); Integer result = task.get(); System.out.println("线程执行的结果为:" + result); } @Override public Integer call() throws Exception { System.out.println("正在进行紧张的计算...."); Thread.sleep(3000); return 1; } }
五、定时器
import java.util.Timer; import java.util.TimerTask; public class Demo5 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { // 实现定时任务 System.out.println("timertask is run"); } }, 0, 1000); } }
六、线程池的实现
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo6 { public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { threadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } threadPool.shutdown(); } }
七、Lambda表达式实现
import java.util.Arrays; import java.util.List; public class Demo7 { public static void main(String[] args) { List<Integer> values = Arrays.asList(10,20,30,40); int res = new Demo7().add(values); System.out.println("计算的结果为:" + res); } public int add (List<Integer> values) { // values.parallelStream().forEach(System.out :: println); return values.parallelStream().mapToInt( i -> i * 2).sum(); } }
八、Spring实现多线程
spring通过任务执行器TaskExecutor来实现多线程与并发编程。通常使用ThreadPoolTaskExecutor来实现一个基于线程池的TaskExecutor.
首先你要实现AsyncConfigurer 这个接口,目的是开启一个线程池.
import java.util.concurrent.Executor; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; /** * 注入一个线程池 * @author mingge * */ @Configuration @ComponentScan("com.foreveross.service.weixin.test.thread") @EnableAsync public class TaskExecutorConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor=new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(20); taskExecutor.setQueueCapacity(25); taskExecutor.initialize(); return taskExecutor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; } }
然后注入一个类,实现你的业务,并在你的Bean的方法中使用@Async注解来声明其是一个异步任务
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; /** * 线程池任务 * @author mingge * */ @Service public class TaskService { @Async public void executeAsyncTask(int i){ System.out.println("执行异步任务:"+i); } @Async public void executeAsyncTask1(int i){ System.out.println("执行异步任务1:"+(i+i)); } }
最后通过测试,可以看到你的实现是异步执行了.
import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * * @author mingge * */ public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(TaskExecutorConfig.class); TaskService taskService=context.getBean(TaskService.class); for(int i=0;i<20;i++){ taskService.executeAsyncTask(i); taskService.executeAsyncTask1(i); } //最后可以根据结果可以看出结果是并发执行而不是顺序执行的呢 context.close(); } }
方式二:XML方式
spring就提供了ThreadPoolTaskExecutor这个类来实现线程池,线程池是啥,可以理解为数据源,或者有一堆线程的池子也行
在spring配置中我们可以写好如下代码(大致意思都在注释中,不多说了,百度也一堆):
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 核心线程数 --> <property name="corePoolSize" value="5" /> <!-- 最大线程数 --> <property name="maxPoolSize" value="10" /> <!-- 队列最大长度 >=mainExecutor.maxSize --> <property name="queueCapacity" value="25" /> <!-- 线程池维护线程所允许的空闲时间 --> <property name="keepAliveSeconds" value="3000" /> <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃. --> <property name="rejectedExecutionHandler"> <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" /> </property> </bean>
然后定义一个component组件,然后线程的引用就十分简单了,只要把这个线程扔进这个线程池子就行了
@Component public class FileCutter { @Autowired private TaskExecutor taskExecutor; public void filesMng(String path, String fileName) { this.taskExecutor.execute(new CutFilesThread(path,fileName)); } private class CutFilesThread implements Runnable { private String path; private String fileName; private CutFilesThread(String path, String fileName) { super(); this.path = path; this.fileName = fileName; } @Override public void run() { System.out.println("barry... run..."); // display(path, fileName); } }
最后在你所需要的地方就可以调用这个组件了,不论是service还是controller都行
@Autowired private FileCutter fileCutter; @RequestMapping("/cut") @ResponseBody public Object cut(){ fileCutter.filesMng("your path", "your fileName"); return "success"; }
另外可以参考:https://blog.csdn.net/king_kgh/article/details/76022136
参考资料:
龙果学院《Java并发编程原理与实战》